﻿using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.ObjectPool;
using ZqUtils.Core.Helpers;
using ZqUtils.Core.Extensions;
using SysConsole = System.Console;

namespace ZqUtils.Core.Console
{
    /// <summary>
    /// 单例测试实体
    /// </summary>
    public class TestObject
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public TestObject()
        {

        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="name"></param>
        /// <param name="age"></param>
        public TestObject(string name, int age)
        {
            SysConsole.WriteLine($"姓名：{name}，年龄：{age}");
        }

        /// <summary>
        /// 单例静态实例
        /// </summary>
        public static TestObject Instance => SingletonHelper<TestObject>.GetInstance("张三", 20);
    }

    /// <summary>
    /// 测试实体
    /// </summary>
    public class TestEntity
    {
        /// <summary>
        /// 姓名
        /// </summary>
        [Required(ErrorMessage = "姓名不能为空")]
        public string Name { get; set; }

        /// <summary>
        /// 地址
        /// </summary>
        [Required(ErrorMessage = "地址不能为空")]
        public string Address { get; set; }

        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateDate { get; set; } = DateTime.Now;
    }

    /// <summary>
    /// 对象池实体
    /// </summary>
    public class ObjectPoolEntity
    {
        /// <summary>
        /// 对象池
        /// </summary>
        private static readonly ConcurrentDictionary<string, Lazy<ObjectPoolHelper<ObjectPoolEntity>>> _pool = new ConcurrentDictionary<string, Lazy<ObjectPoolHelper<ObjectPoolEntity>>>();

        /// <summary>
        /// 对象池获取实例
        /// </summary>
        /// <returns></returns>
        public ObjectPoolEntity GetInstance(string key = "defaultkey")
        {
            if (!_pool.ContainsKey(key))
            {
                var objectPool = new Lazy<ObjectPoolHelper<ObjectPoolEntity>>(() => new ObjectPoolHelper<ObjectPoolEntity>(() => new ObjectPoolEntity()));
                _pool.GetOrAdd(key, objectPool);
                return objectPool.Value.GetObject();
            }
            else
            {
                return _pool[key].Value.GetObject();
            }
        }
    }

    /// <summary>
    /// 自定义对象池策略
    /// </summary>
    public class CustomPooledObjectPolicy : IPooledObjectPolicy<TestEntity>
    {
        /// <summary>
        /// 创建对象
        /// </summary>
        /// <returns></returns>
        public TestEntity Create()
        {
            return new TestEntity
            {
                Name = "测试名称",
                Address = "测试地址"
            };
        }

        /// <summary>
        /// 是否允许归返对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public bool Return(TestEntity obj)
        {
            return true;
        }
    }

    /// <summary>
    /// Program
    /// </summary>
    public class Program
    {
        public static void Main(string[] args)
        {
            #region 二维码/条形码/验证码
            //var str = CodeHelper.CreateQrBase64("zhangq", @"D:\Utils.Png");
            //SysConsole.WriteLine(str);
            //var res = CodeHelper.ReadCode(@"D:\qr1.png");
            //var code = $"data:image/png;base64,{Convert.ToBase64String(CodeHelper.CreateValidateGraphic("zhangq"))}";
            #endregion

            #region Zip文件解压缩
            //压缩
            //ZipHelper.Zip(@"D:\月度考核表", @"D:\月度考核表.zip");

            //解压缩
            //ZipHelper.UnZip(@"C:\月度考核表.zip", @"C:\");
            #endregion

            #region 实体验证
            var entity = new List<TestEntity>
            {
                new TestEntity
                {
                    Name = "张三",
                    Address = ""
                }
            };
            var (isValid, validationResults) = entity.IsValidWithResult();
            if (!isValid)
            {
                SysConsole.WriteLine(string.Join("；", validationResults.Select(x => x.ErrorMessage)));
            }
            #endregion

            #region 对象池
            var instance = new ObjectPoolEntity().GetInstance();
            instance = new ObjectPoolEntity().GetInstance();
            SysConsole.WriteLine(instance.ToJson());
            #endregion

            #region 微软对象池
            //方法一
            //var policy = new DefaultPooledObjectPolicy<TestEntity>();
            var policy = new CustomPooledObjectPolicy();
            //初始化对象池，并设置大小为10
            var pool1 = new DefaultObjectPool<TestEntity>(policy, 10);
            //对象池获取对象
            var testEntity1 = pool1.Get();
            pool1.Return(testEntity1);
            var testEntity2 = pool1.Get();
            pool1.Return(testEntity2);
            SysConsole.WriteLine(testEntity1 == testEntity2);

            //方法二
            var services = new ServiceCollection();
            //设置线程池大小
            services.AddSingleton<ObjectPoolProvider>(new DefaultObjectPoolProvider { MaximumRetained = 10 });
            services.AddSingleton(s =>
            {
                var provider = s.GetRequiredService<ObjectPoolProvider>();
                return provider.Create(new CustomPooledObjectPolicy());
            });
            var serviceProvider = services.BuildServiceProvider();
            var pool2 = serviceProvider.GetService<ObjectPool<TestEntity>>();
            //对象池获取对象
            testEntity1 = pool2.Get();
            pool2.Return(testEntity1);
            testEntity2 = pool2.Get();
            pool2.Return(testEntity2);
            SysConsole.WriteLine(testEntity1 == testEntity2);

            //方法三，采用封装过后的微软对象池
            var pool = new MicrosoftObjectPool<TestEntity>(creater: () => new TestEntity { Name = "张三", Address = "测试地址" });
            var entity1 = pool.Get();
            pool.Return(entity1);
            var entity2 = pool.Get();
            pool.Return(entity2);
            SysConsole.WriteLine(entity1 == entity2);
            #endregion

            #region 单例
            var o = TestObject.Instance;
            o = TestObject.Instance;
            #endregion
            SysConsole.ReadLine();
        }
    }
}
